package com.xdl.common.wechat.util;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xdl.common.utils.RestUtil;
import com.xdl.common.wechat.dto.WeixinPhoneDecryptInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class AESForWeixinGetPhoneNumber {

    //加密方式
    private static String keyAlgorithm = "AES";
    //避免重复new生成多个BouncyCastleProvider对象，因为GC回收不了，会造成内存溢出
    //只在第一次调用decrypt()方法时才new 对象
    private static boolean initialized = false;
    //用于Base64解密
    private Base64.Decoder decoder = Base64.getDecoder();

    //待解密的数据
    private String originalContent;
    //会话密钥sessionKey
    private String encryptKey;
    //加密算法的初始向量
    private String iv;

    public AESForWeixinGetPhoneNumber(String originalContent,String encryptKey,String iv) {
        this.originalContent = originalContent;
        this.encryptKey = encryptKey;
        this.iv = iv;
    }

    /**
     * AES解密
     * 填充模式AES/CBC/PKCS7Padding
     * 解密模式128
     *
     * @return 解密后的信息对象
     */
    public WeixinPhoneDecryptInfo decrypt() {
        initialize();
        try {
            //数据填充方式
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(decoder.decode(this.encryptKey), keyAlgorithm);
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(decoder.decode(this.iv)));
            byte[]data = cipher.doFinal(decoder.decode(this.originalContent));
            String datastr = new String(data, StandardCharsets.UTF_8);
            return JSON.toJavaObject(JSON.parseObject(datastr),WeixinPhoneDecryptInfo.class);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        }
    }

    /**BouncyCastle作为安全提供，防止我们加密解密时候因为jdk内置的不支持改模式运行报错。**/
    private static void initialize() {
        if (initialized){
            return;
        }
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    // 生成iv
    private static AlgorithmParameters generateIV(byte[] iv) throws NoSuchAlgorithmException, InvalidParameterSpecException {
        AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm);
        params.init(new IvParameterSpec(iv));
        return params;
    }

    public static JSONObject getSessionKey(){
    //https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
        JSONObject params=new JSONObject();
        params.put("appid","wx4dba30a73438c4a0");
        params.put("secret","83dda801dd13505a8a037f9fa5fcc084");
        params.put("grant_type","authorization_code");
        params.put("js_code","011DoKFa1erOsC0ANmFa1i1zoW1DoKFl");
        JSONObject object = RestUtil.get("https://api.weixin.qq.com/sns/jscode2session", params);
        return object;
    }


    public static void main(String[] args) {
        String encryptedData="rUOQW3zWGwKhTk7W6T070dFOMMZB5zz86IoPfZ8zoKq9hTf/x2g11+cwR3f7ThS/lKpa81hPzH7FevGkjkGvLQXETqUW4aq3xYJvPKx0c/bnyNE/+Cmierocpt+i0Jh2Wyv3jkSYOmVZJY5QIDWvRCf0+ZZsTkg2F5iJZVctbWNwwsHDbG1DipC6Xw0MYdseo5lJT6QOsR+kzch9oYS6pA==";
        String iv="GVC02gbKx4RPPym2nYYp+w==";
        String appId="wx4dba30a73438c4a0";
        JSONObject object = getSessionKey();
        String sessionKey= String.valueOf(object.get("session_key"));
        AESForWeixinGetPhoneNumber aes=new AESForWeixinGetPhoneNumber(encryptedData,sessionKey,iv);
        WeixinPhoneDecryptInfo info=aes.decrypt();
        if (null==info){
            System.out.println("error");
        }else {
            if (!info.getWeixinWaterMark().getAppid().equals(appId)){
                System.out.println("wrong appId");
            }
            System.out.println(info.toString());
        }
    }

}
